import { useState, useEffect, Dispatch, SetStateAction } from 'react';
import { flushSync } from 'react-dom';
import { createRoot } from 'react-dom/client';
import clsx from 'clsx';
import './index.less';

interface Options {
  onClose?: () => void;
  multiple?: number;
  win?: number;
  text?: string;
}

interface Message {
  type: string;
  duration: number;
  options?: Options;
}

let messageQueue: Array<Message> = [];
let updateMessages: Dispatch<SetStateAction<Message[]>>;

const MessageComponent = ({ type, duration, options }: Message) => {
  const [fadeOut, setFadeOut] = useState(false);

  useEffect(() => {
    const timer = setTimeout(() => setFadeOut(true), duration - 300); // 开始渐出动画
    const removeTimer = setTimeout(() => options?.onClose && options.onClose(), duration);
    return () => {
      clearTimeout(timer);
      clearTimeout(removeTimer);
    };
  }, [duration, options]);

  return (
    <div
      className={clsx('message', type)}
      style={{
        animation: `${fadeOut ? 'fadeOut' : 'fadeIn'} 300ms`
      }}
    >
      {
        type === 'error' && options?.text
      }
    </div>
  );
};

const MessageContainer = () => {
  const [messages, setMessages] = useState<Array<Message>>([]);

  updateMessages = setMessages;

  return (
    <div className="message-container">
      {messages.map((msg, index) => (
        <MessageComponent key={index} type={msg.type} duration={msg.duration} options={msg.options} />
      ))}
    </div>
  );
};

const ensureMessageRoot = () => {
  let messageRoot = document.getElementById('message-root');
  if (!messageRoot) {
    flushSync(() => {
      messageRoot = document.createElement('div');
      messageRoot.id = 'message-root';
      document.body.appendChild(messageRoot);
      const root = createRoot(messageRoot);
      root.render(<MessageContainer />);
    });
  }
  return messageRoot;
};

const createMessage = (type: string, duration = 3000, options?: Options) => {
  ensureMessageRoot();

  const message = { type, duration, options };
  messageQueue.push(message);
  updateMessages([...messageQueue]);

  setTimeout(() => {
    messageQueue = messageQueue.filter(msg => msg !== message);
    updateMessages([...messageQueue]);
  }, duration);
};

export default {
  error: (duration = 3000, options?: Options) => createMessage('error', duration, options),
};
